#include "BankAccount.hh"
#include <fstream>
#include <iomanip>
#include <iostream>

namespace BankingSystem {

BankAccount::BankAccount(const std::string& id, const std::string& owner, double initialBalance)
    : accountId(id), ownerName(owner), balance(initialBalance) {
    transactions.reserve(100); 
}

void BankAccount::addTransaction(const Transaction& transaction) {
    transactions.push_back(transaction);
}

bool BankAccount::generateReport(const std::string& filename) const {
    std::ofstream file(filename);
    if (!file.is_open()) {
        std::cout << "Error: Could not create report file: " << filename << "\n";
        return false;
    }

    file << "Transaction Report for Account: " << accountId << "\n";
    file << "Account Type: " << getAccountType() << "\n";
    file << "Owner: " << ownerName << "\n";
    file << "Balance: " << std::fixed << std::setprecision(2) << balance << "\n\n";
    file << "Transactions:\n";
    file << std::left << std::setw(10) << "ID"
         << std::setw(20) << "Date"
         << std::setw(15) << "Type"
         << std::setw(10) << "Amount"
         << "Note\n";
    file << std::string(65, '-') << "\n";

    for (const auto& t : transactions) {
        file << std::left << std::setw(10) << t.getTransactionId()
             << std::setw(20) << t.getDate()
             << std::setw(15) << t.getType()
             << std::fixed << std::setprecision(2) << std::setw(9) << t.getAmount()
             << t.getNote() << "\n";
    }

    file.close();
    std::cout << "Report generated as " << filename << "\n";
    return true;
}

SavingsAccount::SavingsAccount(const std::string& id, const std::string& owner, double initialBalance)
    : BankAccount(id, owner, initialBalance) {}

bool SavingsAccount::deposit(double amount, const std::string& note) {
    std::cout << "Error: Deposits not allowed for Savings Account.\n";
    return false;
}

bool SavingsAccount::withdraw(double amount, const std::string& note) {
    std::cout << "Error: Withdrawals not allowed for Savings Account.\n";
    return false;
}

bool SavingsAccount::transferTo(BankAccount* destination, double amount, const std::string& note) {
    if (!destination) {
        std::cout << "Error: Invalid destination account.\n";
        return false;
    }
    if (amount <= 0 || amount > balance || amount > 1000000.0) {
        std::cout << "Error: Invalid transfer amount (must be positive and less than 1,000,000).\n";
        return false;
    }
    if (destination->getOwnerName() != ownerName || destination->getAccountType() != "Checking") {
        std::cout << "Error: Savings can only transfer to same customer's Checking Account.\n";
        return false;
    }

    balance -= amount;
    destination->balance += amount;

    Transaction t("T" + std::to_string(Transaction::getNextId()), amount, "Transfer Out", note);
    addTransaction(t);
    destination->addTransaction(Transaction("T" + std::to_string(Transaction::getNextId()), amount, "Transfer In", note));

    std::cout << "Transfer successful! New balance: " << std::fixed << std::setprecision(2) << balance << "\n";
    return true;
}

CheckingAccount::CheckingAccount(const std::string& id, const std::string& owner, double initialBalance)
    : BankAccount(id, owner, initialBalance) {}

bool CheckingAccount::deposit(double amount, const std::string& note) {
    if (amount <= 0 || amount > 1000000.0) {
        std::cout << "Error: Invalid deposit amount (must be positive and less than 1,000,000).\n";
        return false;
    }

    balance += amount;
    addTransaction(Transaction("T" + std::to_string(Transaction::getNextId()), amount, "Deposit", note));
    std::cout << "Deposit successful! New balance: " << std::fixed << std::setprecision(2) << balance << "\n";
    return true;
}

bool CheckingAccount::withdraw(double amount, const std::string& note) {
    if (amount <= 0 || amount > balance || amount > 1000000.0) {
        std::cout << "Error: Invalid withdrawal amount (must be positive, less than balance, and less than 1,000,000).\n";
        return false;
    }

    balance -= amount;
    addTransaction(Transaction("T" + std::to_string(Transaction::getNextId()), amount, "Withdrawal", note));
    std::cout << "Withdrawal successful! New balance: " << std::fixed << std::setprecision(2) << balance << "\n";
    return true;
}

bool CheckingAccount::transferTo(BankAccount* destination, double amount, const std::string& note) {
    if (!destination) {
        std::cout << "Error: Invalid destination account.\n";
        return false;
    }
    if (amount <= 0 || amount > balance || amount > 1000000.0) {
        std::cout << "Error: Invalid transfer amount (must be positive, less than balance, and less than 1,000,000).\n";
        return false;
    }

    balance -= amount;
    destination->balance += amount;

    addTransaction(Transaction("T" + std::to_string(Transaction::getNextId()), amount, "Transfer Out", note));
    destination->addTransaction(Transaction("T" + std::to_string(Transaction::getNextId()), amount, "Transfer In", note));

    std::cout << "Transfer successful! New balance: " << std::fixed << std::setprecision(2) << balance << "\n";
    return true;
}

} 